package controller;

import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import model.HitResult;
import model.VirtualMemory;
import service.PageService;
import service.ReplaceService;
import service.ServiceFactory;

/**
 * description: 主界面
 * @return
 */
public class ReplaceOverviewController {

    private PageService pageService = ServiceFactory.getPageService();

    private ReplaceService replaceService = ServiceFactory.getReplaceService();

    private ObservableList<VirtualMemory> virtualMemoryObservableList;

    private ObservableList<HitResult> hitResultObservableList;
//组件 ----------------------------------------------------------------

    @FXML
    private AnchorPane rootAnchorPane;

    //上方工具栏，需要设置背景样式
    @FXML
    private AnchorPane toolAnchorPane;

    @FXML
    private BorderPane rootBorderPane;

    //重新生成按钮
    @FXML
    private Button refreshButton;

    //进度条（目前弃用，改用下方Label
    @FXML
    private ProgressBar progressBar;

    private DoubleProperty progress;

    //进度提示Label
    @FXML
    private Label progressLabel;

    //左上角的生成序列表格
    @FXML
    private TableView<VirtualMemory> addressTableView;

    @FXML
    private TableColumn<VirtualMemory, Integer> numberCol;

    @FXML
    private TableColumn<VirtualMemory, Integer> addressCol;

    @FXML
    private TableColumn<VirtualMemory, Integer> pageCol;

    //左下角的命中率预览表格
    @FXML
    private TableView replaceHitTableView;

    @FXML
    private TableColumn pageSizeCol;

    @FXML
    private TableColumn FIFOCol;

    @FXML
    private TableColumn LRUCol;

    @FXML
    private TableColumn OPTCol;

    //统计图表
    @FXML
    private LineChart<Integer, Double> hitRateLineChart;

    @FXML
    private NumberAxis xAxis;

    @FXML
    private NumberAxis yAxis;
    //统计图表数据线
    private XYChart.Series<Integer, Double> seriesOfFIFO;
    private XYChart.Series<Integer, Double> seriesOfLRU;
    private XYChart.Series<Integer, Double> seriesOfOPT;
//初始化 --------------------------------------------------------------
    @FXML
    public void initialize() {

        //可视化属性的初始化
        this.virtualMemoryObservableList = FXCollections.observableArrayList();
        this.hitResultObservableList = FXCollections.observableArrayList();
        this.progress = new SimpleDoubleProperty();

        //更新部分样式
        toolAnchorPane.setStyle("-fx-background-color: rgba(153,153,153,0.28)");

        //进度条隐藏
        progressBar.setOpacity(0); //隐藏状态
        progress.set(0.0);
        //数据绑定
        progressBar.progressProperty().bind(progress);
        //确定表格单元和属性的对应关系
        numberCol.setCellValueFactory(new PropertyValueFactory<VirtualMemory, Integer>("number"));
        addressCol.setCellValueFactory(new PropertyValueFactory<VirtualMemory, Integer>("address"));
        pageCol.setCellValueFactory(new PropertyValueFactory<VirtualMemory, Integer>("page"));
        addressCol.setCellValueFactory(new PropertyValueFactory<VirtualMemory, Integer>("address"));

        pageSizeCol.setCellValueFactory(new PropertyValueFactory<HitResult, Integer>("pageSize"));
        FIFOCol.setCellValueFactory(new PropertyValueFactory<HitResult, Double>("hitOfFIFO"));
        LRUCol.setCellValueFactory(new PropertyValueFactory<HitResult, Double>("hitOfLRU"));
        OPTCol.setCellValueFactory(new PropertyValueFactory<HitResult, Double>("hitOfOPT"));

        //初始化统计表格
        seriesOfFIFO = new XYChart.Series<>();
        seriesOfFIFO.setName("FIFO");
        seriesOfLRU = new XYChart.Series<>();
        seriesOfLRU.setName("LRU");
        seriesOfOPT = new XYChart.Series<>();
        seriesOfOPT.setName("OPT");

        hitRateLineChart.getData().add(seriesOfFIFO);
        hitRateLineChart.getData().add(seriesOfLRU);
        hitRateLineChart.getData().add(seriesOfOPT);

        //装填数据
        fillAddressTableView();
        fillReplaceHitTableView();
        fillChart();

        //响应事件初始化
        progressBarListener();
        progressLabel.setText("载入完成");
    }

//组件响应 -------------------------------------------------------------

    //重新生成按钮的事件
    public  void refreshButtonAction() {
        progressLabel.setText("正在生成....");
        refreshButton.setDisable(true);

        fillAddressTableView();
        fillReplaceHitTableView();
        fillChart();

        loading();  //线程载入和调用位置有关系，放在fillAddressTableView()前会卡死
    }

    //载入新线程，模拟短暂延时，加强响应
    public void loading() {
        Platform.runLater(()->{
            try {
                Thread.sleep(1000);
                refreshButton.setDisable(false);
                progressLabel.setText("");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }
    //进度条的监听
    public void progressBarListener() {
        progress.addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                if (progress.getValue() > 0.0 && progress.getValue() <= 1) {
                    progressBar.setOpacity(1);
                    return;
                }
                progressBar.setOpacity(0);
            }
        });
    }

//私有方法 -------------------------------------------------------------

    //填充地址表格
    private void fillAddressTableView() {
        //生成地址
        virtualMemoryObservableList.clear();    //TODO clear和removeAll的区别
        virtualMemoryObservableList.addAll(pageService.generateAddress());
        //清空表格
        addressTableView.getItems().removeAll();
        //重新装填
        addressTableView.setItems(virtualMemoryObservableList);
    }

    //填充命中率表格
    private void fillReplaceHitTableView() {
        //先清空
        replaceHitTableView.getItems().clear();
        hitResultObservableList.clear();
        //重新装填
        for (int i = 4; i <= 40; i++) {
            hitResultObservableList.add(
                    new HitResult(i,
                            replaceService.replaceWithFIFO(virtualMemoryObservableList, i),
                            replaceService.replaceWithLRU(virtualMemoryObservableList, i),
                            replaceService.replaceWithOPT(virtualMemoryObservableList, i)
                    ));
        }
        replaceHitTableView.getItems().addAll(hitResultObservableList);
    }

    //填充统计图表
    private void fillChart() {
        //清空数据
        seriesOfFIFO.getData().clear();
        seriesOfLRU.getData().clear();
        seriesOfOPT.getData().clear();

        //填充直线数据
        for (HitResult hitResult :
                hitResultObservableList) {
            seriesOfFIFO.getData().add(new XYChart.Data<>(hitResult.getPageSize(), hitResult.getHitOfFIFO()*100));
            seriesOfLRU.getData().add(new XYChart.Data<>(hitResult.getPageSize(), hitResult.getHitOfLRU()*100));
            seriesOfOPT.getData().add(new XYChart.Data<>(hitResult.getPageSize(), hitResult.getHitOfOPT()*100));
        }
    }

    //进度条组件缓慢增长
    private void updateProgress(double dest) {
        while (progress.getValue() < dest) {
            progress.setValue(progress.getValue() + 0.01);
        }
        if (progress.getValue() >= 1.0) {
            progress.setValue(0.0);
        }
    }
}
